/**
============================================================================
 File Name    : touch.c
 Author       : findstr
 Email        : findstr@sina.com
 Description  : (C)  findstr
               @resistor touch pad driver
 Edit History : 2013/09/20 File changed.
 Rev          : 0.1
============================================================================
*/
#include "stm32f10x.h"
#include "trace.h"
#include "stdlib.h"
#include "math.h"
#include "color.h"
#include "lcd.h"
#include "xpt2046.h"

#define	SW_SPI	1

#define	CHX_CMD		0x90
#define	CHY_CMD		0xD0

#define	SCK_L	GPIO_ResetBits(GPIOA, GPIO_Pin_5)
#define	SCK_H	GPIO_SetBits(GPIOA, GPIO_Pin_5)

#define	MO_L	GPIO_ResetBits(GPIOA, GPIO_Pin_7)
#define	MO_H	GPIO_SetBits(GPIOA, GPIO_Pin_7)

#define	CS_L	GPIO_ResetBits(GPIOB, GPIO_Pin_5)
#define	CS_H	GPIO_SetBits(GPIOB, GPIO_Pin_5)

#define	MI()	GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)

#if	SW_SPI
static void sw_spi_init()
{
	GPIO_InitTypeDef	GPIO_InitStruct;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5  | GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	/* cs */
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);

	/* cs */
	GPIO_SetBits(GPIOB, GPIO_Pin_5);
}
static void sw_spi_write(u8 nr)
{
	u8 i;
	for (i = 0; i < 8; i++) {
		if (nr & 0x80)
			MO_H;
		else
			MO_L;
		nr <<= 1;
		SCK_L;
		SCK_H;
	}
}
static void sw_spi_assert()
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_5);
}
static void sw_spi_deassert()
{
	GPIO_SetBits(GPIOB, GPIO_Pin_5);
}

#endif


static u16 readxy(u8 cmd)
{
	u8 i;
	u16 val;

#if	SW_SPI
	SCK_L;
	MO_L;
	sw_spi_assert();
	sw_spi_write(cmd);
	delay_us(6);
	SCK_L;
	delay_us(1);
	SCK_H;
	SCK_L;

	val = 0;
	for (i = 0; i < 16; i++) {
		val <<= 1;
		SCK_L;
		SCK_H;
		if (MI())
			val |= 0x01;
	}

	val >>= 4;
	sw_spi_deassert();
#else
	spi1_assert();

	spi_write(SPI1, cmd);
	delay_us(6);

	val = spi_read(SPI1);
	val <<= 8;
	val |= spi_read(SPI1);

	val >>= 3;
	spi1_deassert();
#endif
	return val;
}
u32 xpt2046_readpos(u32 *x, u32 *y)
{
	const u32 count = 5;
	u8 i;
	u32 maxx, minx, maxy, miny, tmpx, tmpy;
	u32 sumx, sumy;

	sumx = 0;
	maxx = 0;
	minx = 0xffff;

	sumy = 0;
	maxy = 0;
	miny = 0xffff;
	for (i = 0; i < count; i++) {
		tmpx = readxy(CHX_CMD);
		tmpy = readxy(CHY_CMD);
		sumx += tmpx;
		sumy += tmpy;

		if (maxx < tmpx)
			maxx = tmpx;
		if (minx > tmpx)
			minx = tmpx;

		if (maxy < tmpy)
			maxy = tmpy;
		if (miny > tmpy)
			miny = tmpy;
	}
	sumx -= minx;
	sumx -= maxx;
	*x = sumx / (count - 2);

	sumy -= miny;
	sumy -= maxy;
	*y = sumy / (count - 2);

	return 0;
}

void xpt2046_init()
{
	GPIO_InitTypeDef	GPIO_InitStruct;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

	/* interrupt */
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStruct);

	#if SW_SPI
		sw_spi_init();
	#else
		spi1_init();
	#endif
}

u8 xpt2046_penirq()
{
	return GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_3);
}
